package com.fw4j.jdbc.tools;

import java.io.PrintWriter;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import org.objectweb.asm.util.TraceClassVisitor;

/**
 * @author 穆仁超
 * 动态生成Entity类
 * 日期 2013-12-27 16:34
 * 我的QQ群：32894018
 */
public class CreateEntity extends ClassLoader{
	private ClassWriter cw1 = null;
	private TraceClassVisitor cw = null;
	private MethodVisitor mv = null;
	private GeneratorAdapter ga = null;
	private String className = null;
	private static java.util.Map<String,byte[]> bytecodes = new java.util.HashMap<String,byte[]>();
	public CreateEntity(){
		cw1 = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		cw = new TraceClassVisitor(cw1, new PrintWriter(System.out));
	}
	public void createClass(String className, String extendsClass,
			String[] extendsInterfaces) {
		if(extendsClass == null) extendsClass = "java/lang/Object";
		this.className = className;
		cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, this.className, null,extendsClass, extendsInterfaces);
		mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
		mv.visitVarInsn(Opcodes.ALOAD, 0);
		mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
		mv.visitInsn(Opcodes.RETURN);
		mv.visitMaxs(1,1);
		mv.visitEnd();
	}
	public Object loadClass(){
		cw.visitEnd();
		try {
			byte[] code = cw1.toByteArray();
			bytecodes.put(this.className, code);
			Class cl = this.defineClass(this.className,code, 0, code.length);
			return cl.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return null;
	}

	public void addField(String fieldName, Class type) {
		cw.visitField(Opcodes.ACC_PRIVATE, fieldName, Type.getDescriptor(type), null,null).visitEnd();
	}
		
	public void addSetter(String method,String field,Class fieldType){
		Method m = Method.getMethod(method,true);
		ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, m, null,null,cw);
		ga.loadThis();
		ga.loadArg(0);
		ga.putField(Type.getType(this.className), field, Type.getType(fieldType));
		ga.returnValue();
		ga.endMethod();
		
	}

	public void addGetter(String method,String field,Class fieldType){
		Method m = Method.getMethod(method,true);
		ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, m, null,null,cw);
		ga.loadThis();
		ga.getField(Type.getType(this.className), field, Type.getType(fieldType));
		ga.returnValue();
		ga.endMethod();
	}
	
	public Object getInstance(String key){
		if(bytecodes.containsKey(key)){
			try {
				byte[] code = bytecodes.get(key);
				Class cl = this.defineClass(this.className,code, 0, code.length);
				return cl.newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		return null;
	}
}
